package at.ac.tuwien.dse.health.messenger;

import at.ac.tuwien.dse.health.entity.*;
import org.springframework.transaction.annotation.Transactional;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.io.Serializable;
import java.util.Date;

import static org.apache.commons.lang3.ArrayUtils.addAll;
import static org.apache.commons.lang3.ArrayUtils.nullToEmpty;

/**
 * @author Bernhard Nickel
 * @author Gregor Schauer
 * @author Dominik Strasser
 */
@Transactional
public class MessageService {
	@Inject
	DynamicMethodInvoker dynamicMethodInvoker;
	@PersistenceContext
	EntityManager entityManager;

	/**
	 * Saves the given {@link Message}.
	 *
	 * @param message the message to save
	 * @return the message
	 */
	Message persist(Message message) {
		entityManager.persist(message);
		return message;
	}

	/**
	 * Finds the {@link Account} of a certain type with the given identifier.
	 *
	 * @param userType the account type
	 * @param id the identifier
	 * @return the account
	 */
	Account findAccount(Class<? extends Serializable> userType, long id) {
		String query;
		if (userType == Patient.class) {
			query = Account.BY_PATIENT_ID;
		} else if (userType == Doctor.class) {
			query = Account.BY_DOCTOR_ID;
		} else if (userType == Hospital.class) {
			query = Account.BY_HOSPITAL_ID;
		} else {
			throw new IllegalArgumentException(String.format("Unknown user type '%s'", userType));
		}
		return entityManager.createNamedQuery(query, Account.class).setParameter("id", id).getSingleResult();
	}

	/**
	 * Finds the {@link SurgerySlot} of a certain type with the given identifier.
	 *
	 * @param id the identifier
	 * @return the account
	 */
	public SurgerySlot findSlot(long id) {
		return entityManager.find(SurgerySlot.class, id);
	}

	/**
	 * Creates a new {@link Message} of a certain type for the given {@link at.ac.tuwien.dse.health.event.type.Event}.
	 *
	 *
	 * @param eventValue the value of the event to create a message for
	 * @param messageType the type of the message
	 * @param date the message creation date
	 * @param account the account to deliver the message to
	 * @param args additional arguments
	 * @return the message
	 */
	public Message createMessage(Serializable eventValue, MessageType messageType, Date date, Account account, Object... args) {
		Message message = new Message();
		message.setMessage(String.valueOf(dynamicMethodInvoker.invoke(addAll(nullToEmpty(args), eventValue))));
		message.setTitle(String.valueOf(dynamicMethodInvoker.invoke(eventValue)));
		message.setType(messageType.toString());
		message.setAccount(account);
		message.setSendDate(date);
		return persist(message);
	}
}
